/**
 * 确定性数学包装器
 * 
 * @description
 * 统一接口，根据配置自动选择：浮点数/精确度保留/定点数
 * 最小化代码修改
 */

import { Vector2, RVOMath } from '../rvo/Common';
import { FixedPoint } from './FixedPoint';
import { FixedVector2, FixedRVOMath } from './FixedVector2';
import { PrecisionNumber } from './PrecisionNumber';
import { PrecisionVector2, PrecisionRVOMath } from './PrecisionVector2';
import { DeterministicConfig, DeterministicMode } from './DeterministicConfig';

/**
 * 通用向量类型
 */
export type DVector2 = Vector2 | PrecisionVector2 | FixedVector2;

/**
 * 通用数字类型
 */
export type DNumber = number | PrecisionNumber | FixedPoint;

/**
 * 确定性向量包装器
 */
export class DVector {
    
    /**
     * 创建向量（根据配置自动选择类型）
     */
    static create(x: number = 0, y: number = 0): DVector2 {
        switch (DeterministicConfig.mode) {
            case DeterministicMode.FIXED:
                return new FixedVector2(x, y);
            case DeterministicMode.PRECISION:
                return new PrecisionVector2(x, y);
            default:
                return new Vector2(x, y);
        }
    }
    
    /**
     * 从现有向量转换
     */
    static from(v: Vector2 | PrecisionVector2 | FixedVector2): DVector2 {
        const mode = DeterministicConfig.mode;
        
        if (mode === DeterministicMode.FIXED) {
            if (v instanceof FixedVector2) return v;
            if (v instanceof PrecisionVector2) {
                return new FixedVector2(v.x.value, v.y.value);
            }
            return FixedVector2.fromVector2(v as Vector2);
        }
        
        if (mode === DeterministicMode.PRECISION) {
            if (v instanceof PrecisionVector2) return v;
            if (v instanceof FixedVector2) {
                return new PrecisionVector2(v.x.toNumber(), v.y.toNumber());
            }
            return PrecisionVector2.fromVector2(v as Vector2);
        }
        
        // FLOAT mode
        if (v instanceof Vector2) return v;
        if (v instanceof PrecisionVector2) {
            return new Vector2(v.x.value, v.y.value);
        }
        return (v as FixedVector2).toVector2();
    }
    
    /**
     * 向量加法
     */
    static add(v1: DVector2, v2: DVector2): DVector2 {
        if (v1 instanceof FixedVector2) {
            return (v1 as FixedVector2).plus(v2 as FixedVector2);
        }
        if (v1 instanceof PrecisionVector2) {
            return (v1 as PrecisionVector2).plus(v2 as PrecisionVector2);
        }
        return (v1 as Vector2).plus(v2 as Vector2);
    }
    
    /**
     * 向量减法
     */
    static sub(v1: DVector2, v2: DVector2): DVector2 {
        if (v1 instanceof FixedVector2) {
            return (v1 as FixedVector2).minus(v2 as FixedVector2);
        }
        if (v1 instanceof PrecisionVector2) {
            return (v1 as PrecisionVector2).minus(v2 as PrecisionVector2);
        }
        return (v1 as Vector2).minus(v2 as Vector2);
    }
    
    /**
     * 向量缩放
     */
    static scale(v: DVector2, factor: number): DVector2 {
        if (v instanceof FixedVector2) {
            return (v as FixedVector2).scale(factor);
        }
        if (v instanceof PrecisionVector2) {
            return (v as PrecisionVector2).scale(factor);
        }
        return (v as Vector2).scale(factor);
    }
    
    /**
     * 向量归一化
     */
    static normalize(v: DVector2): DVector2 {
        if (v instanceof FixedVector2) {
            return (v as FixedVector2).normalize();
        }
        if (v instanceof PrecisionVector2) {
            return (v as PrecisionVector2).normalize();
        }
        return (v as Vector2).normalize();
    }
    
    /**
     * 向量长度
     */
    static getLength(v: DVector2): number {
        if (v instanceof FixedVector2) {
            return (v as FixedVector2).length().toNumber();
        }
        if (v instanceof PrecisionVector2) {
            return (v as PrecisionVector2).length().value;
        }
        return (v as Vector2).length();
    }
    
    /**
     * 向量长度的平方
     */
    static lengthSqr(v: DVector2): number {
        if (v instanceof FixedVector2) {
            return (v as FixedVector2).lengthSqr().toNumber();
        }
        if (v instanceof PrecisionVector2) {
            return (v as PrecisionVector2).lengthSqr().value;
        }
        return (v as Vector2).lengthSqr();
    }
    
    /**
     * 点积
     */
    static dot(v1: DVector2, v2: DVector2): number {
        if (v1 instanceof FixedVector2) {
            return (v1 as FixedVector2).multiply(v2 as FixedVector2).toNumber();
        }
        if (v1 instanceof PrecisionVector2) {
            return (v1 as PrecisionVector2).multiply(v2 as PrecisionVector2).value;
        }
        return (v1 as Vector2).multiply(v2 as Vector2);
    }
    
    /**
     * 转换为普通 Vector2（用于显示）
     */
    static toVector2(v: DVector2): Vector2 {
        if (v instanceof FixedVector2) {
            return (v as FixedVector2).toVector2();
        }
        if (v instanceof PrecisionVector2) {
            return (v as PrecisionVector2).toVector2();
        }
        return v as Vector2;
    }
}

/**
 * 确定性数学工具包装器
 */
export class DMath {
    
    /**
     * 平方根
     */
    static sqrt(x: number): number {
        const mode = DeterministicConfig.mode;
        
        if (mode === DeterministicMode.FIXED) {
            return FixedPoint.fromNumber(x).sqrt().toNumber();
        }
        if (mode === DeterministicMode.PRECISION) {
            return new PrecisionNumber(x).sqrt().value;
        }
        return Math.sqrt(x);
    }
    
    /**
     * 平方
     */
    static sqr(x: number): number {
        const result = x * x;
        
        if (DeterministicConfig.mode === DeterministicMode.PRECISION) {
            return PrecisionNumber.round(result);
        }
        return result;
    }
    
    /**
     * 绝对值
     */
    static abs(x: number): number {
        return Math.abs(x);
    }
    
    /**
     * 最小值
     */
    static min(a: number, b: number): number {
        return Math.min(a, b);
    }
    
    /**
     * 最大值
     */
    static max(a: number, b: number): number {
        return Math.max(a, b);
    }
    
    /**
     * 向量长度的平方
     */
    static absSq(v: DVector2): number {
        if (v instanceof FixedVector2) {
            return FixedRVOMath.absSq(v as FixedVector2).toNumber();
        }
        if (v instanceof PrecisionVector2) {
            return PrecisionRVOMath.absSq(v as PrecisionVector2).value;
        }
        return RVOMath.absSq(v as Vector2);
    }
    
    /**
     * 向量长度
     */
    static absVec(v: DVector2): number {
        if (v instanceof FixedVector2) {
            return FixedRVOMath.abs(v as FixedVector2).toNumber();
        }
        if (v instanceof PrecisionVector2) {
            return PrecisionRVOMath.abs(v as PrecisionVector2).value;
        }
        return RVOMath.abs(v as Vector2);
    }
    
    /**
     * 向量归一化
     */
    static normalizeVec(v: DVector2): DVector2 {
        if (v instanceof FixedVector2) {
            return FixedRVOMath.normalize(v as FixedVector2);
        }
        if (v instanceof PrecisionVector2) {
            return PrecisionRVOMath.normalize(v as PrecisionVector2);
        }
        return RVOMath.normalize(v as Vector2);
    }
    
    /**
     * 向量叉积
     */
    static det(v1: DVector2, v2: DVector2): number {
        if (v1 instanceof FixedVector2) {
            return FixedRVOMath.det(v1 as FixedVector2, v2 as FixedVector2).toNumber();
        }
        if (v1 instanceof PrecisionVector2) {
            return PrecisionRVOMath.det(v1 as PrecisionVector2, v2 as PrecisionVector2).value;
        }
        return RVOMath.det(v1 as Vector2, v2 as Vector2);
    }
    
    /**
     * 点到线段的距离平方
     */
    static distSqPointLineSegment(v1: DVector2, v2: DVector2, v3: DVector2): number {
        if (v1 instanceof FixedVector2) {
            return FixedRVOMath.distSqPointLineSegment(
                v1 as FixedVector2,
                v2 as FixedVector2,
                v3 as FixedVector2
            ).toNumber();
        }
        if (v1 instanceof PrecisionVector2) {
            return PrecisionRVOMath.distSqPointLineSegment(
                v1 as PrecisionVector2,
                v2 as PrecisionVector2,
                v3 as PrecisionVector2
            ).value;
        }
        return RVOMath.distSqPointLineSegment(
            v1 as Vector2,
            v2 as Vector2,
            v3 as Vector2
        );
    }
    
    /**
     * leftOf 判断
     */
    static leftOf(a: DVector2, b: DVector2, c: DVector2): number {
        if (a instanceof FixedVector2) {
            return FixedRVOMath.leftOf(
                a as FixedVector2,
                b as FixedVector2,
                c as FixedVector2
            ).toNumber();
        }
        if (a instanceof PrecisionVector2) {
            return PrecisionRVOMath.leftOf(
                a as PrecisionVector2,
                b as PrecisionVector2,
                c as PrecisionVector2
            ).value;
        }
        return RVOMath.leftOf(a as Vector2, b as Vector2, c as Vector2);
    }
}

